<template>
  <FormDialogComponent
    ref="addOrEditDialogRef"
    dialogWidth="750px"
    v-model="form"
    :formInline="true"
    :formRules="formRules"
    dialogTitle="菜单"
    :formHeader="formHeader"
    :formUrl="urls.API_URL_BACKSTAGE_PERMISSION_MANAGE"
    :formAction="action"
    :showFormFoot="false"
    @afterSubmitSuccess="afterSubmitSuccess"
  >
    <template #form_parentId="scope">
      <SysPermissionTreeSelect v-model="form!['parentId']" :disabled="scope.item.disabled" :data="table.data" clearable selectWidth="197px" />
    </template>
    <template #form_type>
      <el-radio-group v-model="form!['type']" @change="showFormItemByType">
        <el-radio :value="1" label="菜单" />
        <el-radio :value="2" label="按钮" />
      </el-radio-group>
    </template>
    <template #form_linkType="scope">
      <el-radio-group v-model="form!['linkType']" :disabled="scope.item.disabled" @change="showFormItemByLinkType">
        <el-radio :value="1" label="组件" />
        <el-radio :value="2" label="内链" />
        <el-radio :value="3" label="外链" />
      </el-radio-group>
    </template>
    <template #form_sort>
      <el-input-number
        v-model="form!['sort']"
        :min="-1000"
        :max="1000"
        :precision="0"
        placeholder="升序排列"
        style="width: 197px"
        controls-position="right"
        clearable
      />
    </template>
  </FormDialogComponent>
</template>

<script lang="ts" setup>
import FormDialogComponent from '@/components/base/table/form/FormDialogComponent.vue';
import SysPermissionTreeSelect from '@/components/auth/SysPermissionTreeSelectComponent.vue';

import { defineExpose, defineProps, nextTick, onMounted, reactive, ref, withDefaults } from 'vue';
import type { FormHeader, TableData } from '@/types/interface/base_interface';
import { type Option, yesOrNoDict } from '@/api/dict';
import type { Permission } from '@/types/interface/auth_interface';
import urls from '@/api/request/urls';
// import * as Icons from '@element-plus/icons-vue';

// 接收父容器参数
interface Props {
  table: TableData; // 表格对象，包含表格数据和分页信息。表格数据实际业务并不需要，偷懒写法
  action?: string; // 表单的处理类型，post表示提交，put表示编辑
}
const props = withDefaults(defineProps<Props>(), {
  action: 'post'
});
// 表单元素
const formHeader = ref<FormHeader[]>([
  {
    label: '上级菜单',
    prop: 'parentId',
    type: 'custom'
  },
  {
    label: '菜单类型',
    prop: 'type',
    type: 'custom'
  },
  {
    label: '菜单名称',
    prop: 'name',
    width: '197px'
  },
  {
    label: '打开方式',
    prop: 'linkType',
    type: 'custom'
  },
  {
    label: '下划线',
    prop: 'divider',
    type: 'divider'
  },
  {
    label: '菜单图标',
    prop: 'iconCls',
    type: 'iconSelect',
    width: '197px'
  },
  {
    label: '权限标识',
    prop: 'permission',
    width: '197px'
  },
  {
    label: '组件名称',
    prop: 'component',
    placeholder: '唯一字段，对应router的name属性',
    width: '197px',
    rules: [
      {
        required: true,
        message: '不能为空',
        trigger: 'blur'
      },
      {
        min: 1,
        max: 30,
        message: '必须在1-30个字符之间',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '组件地址',
    prop: 'path',
    placeholder: '路由component属性：/page/permissionmanage/Index.vue',
    width: '197px',
    rules: [
      // 考虑到如果菜单有子菜单并不会打开，因此路径这里不作为必填
      // {
      //   required: true,
      //   message: '不能为空',
      //   trigger: 'blur',
      // },
      {
        max: 200,
        message: '不能超过200个字符',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '路由路径',
    prop: 'route',
    placeholder: '对应router的path',
    width: '197px',
    rules: [
      {
        required: true,
        message: '不能为空',
        trigger: 'blur'
      },
      {
        max: 200,
        message: '不能超过200个字符',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '转发地址',
    prop: 'redirect',
    placeholder: '对应router的redirect',
    width: '197px',
    rules: [
      {
        max: 200,
        message: '不能超过200个字符',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '链接地址',
    prop: 'url',
    width: '197px',
    rules: [
      // {
      //   required: true,
      //   message: '不能为空',
      //   trigger: 'blur'
      // },
      {
        max: 200,
        message: '不能超过200个字符',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '排序',
    prop: 'sort',
    type: 'custom',
    placeholder: '升序排列',
    rules: [
      {
        required: true,
        message: '不能为空',
        trigger: 'blur'
      }
    ]
  },
  {
    label: '是否可见',
    prop: 'display',
    type: 'switch'
  },
  {
    label: '是否可用',
    prop: 'enabled',
    type: 'switch'
  },
  {
    label: '要求登录',
    prop: 'requireAuth',
    type: 'switch'
  }
]);
// 表单对象
const form = ref<Permission>();
let formInit: Permission; // 记录表单第一次传入的值,用于表单重置恢复初始值使用
const addOrEditDialogRef = ref(); // 表单ref对象
// 表单验证规则，用于全局表单验证
const formRules = reactive({
  name: [
    {
      required: true,
      message: '不能为空',
      trigger: 'blur'
    },
    {
      min: 1,
      max: 30,
      message: '必须在1-30个字符之间',
      trigger: 'blur'
    }
  ],
  sort: [
    {
      required: true,
      message: '不能为空',
      trigger: 'blur'
    }
  ]
});
/**
 * 当点击菜单类型和链接类型时，表单的切换动作
 * 1.当菜单类型为按钮时
 * 说明：不涉及前端vue组件和链接的相关属性
 * 2.当菜单类型为菜单时
 * (1)组件
 * 说明：常规模式，即该菜单为组件类型，对应route的一个组件
 * (2)内链
 * 说明：该菜单只负责内部路由跳转，例如某组件已经存在，通过内链可以跳转到其他组件，类似于router的index文件中的redirect属性
 * (3)外链
 * 说明：跳转到外部链接
 */
// 当链接类型发生变化时，下列组件发生变化。下列组件只用于菜单的组件类型
const componentArray = ['component', 'route', 'path', 'redirect', 'url'];
// 当打开方式发生变化时
const showFormItemByLinkType = (value?: number) => {
  if (form.value) {
    if (typeof value !== 'undefined') {
      // 只有通过链接类别触发的函数，才进行值的重新修改
      form.value.linkType = value; // 因为该函数也用于提供给其他方法调用，因此这里加一个赋值。
    }
    if (form.value.type === 1) {
      // 如果是菜单可用
      if (form.value.linkType === 1) {
        // 如果是链接类型是组件
        formHeader.value.forEach((itemNeedEdit: FormHeader) => {
          // 遍历表单元素数组,将所有元素设置为可用
          if (itemNeedEdit.prop === 'url') {
            // 让链接表单消失
            itemNeedEdit.disabled = true;
            itemNeedEdit.show = false;
          } else {
            itemNeedEdit.disabled = false;
            itemNeedEdit.show = true;
          }
        });
      } else if (form.value.linkType === 2 || form.value.linkType === 3) {
        // 如果是内部链接或外部链接，则不需要权限标识和组件地址
        formHeader.value!.forEach((itemNeedEdit: FormHeader) => {
          // 遍历表单元素数组,将所有元素设置为可用
          if (itemNeedEdit.prop === 'path' || itemNeedEdit.prop === 'permission') {
            // 让表单组件地址不可用
            itemNeedEdit.show = false;
            itemNeedEdit.disabled = true;
          }
          if (itemNeedEdit.prop === 'url') {
            // 让表单链接元素可用
            itemNeedEdit.show = true;
            itemNeedEdit.disabled = false;
          }
        });
      }
    }
  }
};
// 根据菜单类型显示表单元素
const showFormItemByType = (value?: number) => {
  if (typeof value !== 'undefined') {
    form.value!.type = value; // 因为该函数也用于提供给其他方法调用，因此这里加一个赋值。
  }
  if (form.value!.type === 1) {
    // 如果是菜单,则所有属性都可用。当切换为菜单时，菜单类型默认为组件
    formHeader.value!.forEach((itemNeedEdit: FormHeader) => {
      // 遍历表单元素数组
      if (itemNeedEdit.prop === 'linkType') {
        itemNeedEdit.disabled = false; // 链接类别表单元素变为可以操作
        showFormItemByLinkType(); // 让其余组件做相应的变化
      }
    });
  } else {
    // 如果是按钮
    form.value!.linkType = 1; // 打开方式恢复为组件类型
    formHeader.value!.forEach((itemNeedEdit: FormHeader) => {
      // 遍历表单元素数组
      if (itemNeedEdit.prop === 'linkType') {
        // 让菜单类型变为不可以操作
        itemNeedEdit.disabled = true;
      } else if (componentArray.includes(itemNeedEdit.prop as string)) {
        // 相关组件不可使用
        itemNeedEdit.disabled = true;
        itemNeedEdit.show = false;
      }
    });
  }
};
// 打开对话框供父组件调用，传入表单对象
const openDialog = (permission: Permission) => {
  formInit = { ...permission }; // 获取初始值，这里要做深拷贝，避免与form对象引用的地址一致，导致无法恢复初始值
  form.value = { ...permission };
  showFormItemByType(); // 根据菜单类型显示表单元素
  addOrEditDialogRef.value!.openDialog();
};
const afterSubmitSuccess = async (resData: any) => {
  if (props.action === 'post') {
    //如果是添加，因为添加默认是不关闭对话框的。所以让表单最新的值等于之前创建时候的初始值
    form.value = { ...formInit };
  } else if (props.action === 'put' || props.action === 'patch') {
    //如果是编辑，让初始值等于成功提交后的表单信息
    formInit = { ...form.value! };
  }
  // 钩子函数，提交表单后的操作
  // form.value = { ...formInit }; // 恢复为表单初始值，必须这样恢复，因为父子组件的传递问题，只认可第一次打开表单的初始值。因此不能用element自带的form重置。
  await nextTick();
  // 重置后的表单元素恢复到菜单类型
  showFormItemByType(1);
};
// 暴露组件给父容器使用
defineExpose({
  openDialog
});
</script>

<style lang="scss" scoped></style>
